"""
1. 使用类搭建 epoll tcp网络并发
2. 具体完成 http请求响应

web 服务程序实现

需求： 根据请求  发送响应
结构： 类
技术点： tcp
        IO ： select     epoll
协议： http协议通信

1. 搭建网络服务
2. [1] 接收客户端（浏览器请求）
   [2] 解析客户端发送的请求
   [3] 根据请求组织数据内容
   [4] 将数据内容形成http响应格式返回给浏览器

"""
from socket import *
from select import *

# 创建tcp套接字
from time import sleep

# 具体处理实现http请求事务
class Handle:
    def __init__(self, html=None):
        self.html = html  # 网页存放位置

    def main(self, conn):
        #接收http请求，解析
        info = self._get_info(conn)
        # print("请求内容：",info)  #测试
        if info:
            # 组织响应发送
            self._send_response(conn,info)

    # 解析请求
    def _get_info(self, conn):
        request=conn.recv(1024)
        if not request:
            return
        # 解析出 请求行--》 请求内容
        info = request.decode().split(" ")[1]
        return info

    # 发送响应
    def _send_response(self, conn, info):
        #考虑：请求内容info（存在则分情况讨论）  不存在
        if info == "/":
            info = "/index.html"
        try:
            frb = open(self.html + info, "rb")
        except: #处理不存在情况
            with open(self.html + "/404.html", "rb") as frb:
                data = frb.read()
                response = self._get_response("404 Not Found", data)
        else:
            response = self._get_response("200 OK", frb.read())
            frb.close()
        finally:
            conn.send(response)


    def _get_response(self, status, data):
        # 组织响应内容
        html = "HTTP/1.1 %s\r\n" % status
        html += "Content-Tpye:image/jpeg\r\n"
        html += "\r\n"
        response = html.encode() + data
        return response


# 搭建IO 并发网络模型
class WebServer:
    def __init__(self, host="", port=0, html = None):
        self.host = host
        self.port = port
        self.html = html  #网页存放位置
        self.address = (host,port)
        self.sock = self._create_sock()
        self.eq = epoll()  # 创建好epoll
        self.map = {} #查找字典
        self.handle = Handle(html)

    # 创建监听套接字
    def _create_sock(self):
        sock = socket()
        sock.bind(self.address)
        sock.setblocking(False) #配合非阻塞，防止系统网络产生的延时
        return sock

    # 处理连接
    def _connect_client(self,fd):
        conn, addr = self.map[fd].accept()
        conn.setblocking(False)
        self.eq.register(conn, EPOLLIN)
        self.map[conn.fileno()] = conn  # 维护字典

    # 启动网络服务
    def start(self):
        self.sock.listen(5)
        self.map[self.sock.fileno()] = self.sock
        print("Listen the port %d" % self.port)
        self.eq.register(self.sock, EPOLLIN)  # 初始关注读行为
        # 循环监控IO 发生
        while True:
            events = self.eq.poll()
            for fd,event in events:
                if fd == self.sock.fileno():
                    self._connect_client(fd)
                elif event == EPOLLIN:
                    # 与客户端交互
                    self.handle.main(self.map[fd])
                    self._close(fd)

    # 关闭连接套接字
    def _close(self, fd):
        self.eq.unregister(fd)
        self.map[fd].close()
        del self.map[fd]  # 从字典删除


if __name__ == '__main__':
    eq_server = WebServer(host="0.0.0.0",port=8881, html="./static")
    eq_server.start()


